home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume10 / cbw / part08 < prev    next >
Encoding:
Text File  |  1987-06-17  |  40.8 KB  |  1,716 lines

  1. Path: seismo!uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i008:  Crypt Breaker's Workbench, Part08/11
  5. Message-ID: <390@uunet.UU.NET>
  6. Date: 19 Jun 87 03:17:17 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1705
  9. Approved: rs@uunet.uu.net
  10.  
  11. Submitted by: Robert W. Baldwin <BALDWIN@XX.LCS.MIT.EDU>
  12. Mod.sources: Volume 10, Issue 8
  13. Archive-name: cbw/Part08
  14.  
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line, then unpack
  18. # it by saving it into a file and typing "sh file".  To overwrite existing
  19. # files, type "sh file -c".  You can also feed this as standard input via
  20. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  21. # will see the following message at the end:
  22. #        "End of archive 8 (of 11)."
  23. # Contents:  stats.c terminal.c
  24. # Wrapped by rs@uunet on Wed Jun 17 18:17:26 1987
  25. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  26. if test -f stats.c -a "${1}" != "-c" ; then 
  27.   echo shar: Will not over-write existing file \"stats.c\"
  28. else
  29. echo shar: Extracting \"stats.c\" \(18796 characters\)
  30. sed "s/^X//" >stats.c <<'END_OF_stats.c'
  31. X/*
  32. X * Statistics routines.
  33. X *
  34. X * Robert W. Baldwin, January 1985.
  35. X * Scoring based on letter pairs added by Bob Baldwin May 1985.
  36. X */
  37. X
  38. X
  39. X#include    <stdio.h>
  40. X#include    <math.h>
  41. X#include    "window.h"
  42. X#include    "specs.h"
  43. X#include    "cipher.h"
  44. X
  45. X
  46. X#define STANDALONE    FALSE
  47. X
  48. X
  49. X
  50. X/* Globals */
  51. Xint        stats1loaded = FALSE;    /* True if letter stats loaded. */
  52. Xchar    *letterstats;            /* Filename to find single letter counts. */
  53. Xint        stats2loaded = FALSE;    /* True if letter pair stats loaded. */
  54. Xchar    *bigramstats;            /* Filename to find letter pair counts. */
  55. X
  56. X
  57. X/* This array contains the single letter frequencies.
  58. X * That is, prob[i] is the probability that a randomly selected
  59. X * plaintext character has ascii value i.
  60. X */
  61. Xfloat    prob[MAXCHAR+1];
  62. Xfloat    pmean, pvar;            /* Mean and variance of above. */
  63. X
  64. X
  65. X/* This array contains the base ten logarithms of the single
  66. X * letter frequencies (probabilities) of ASCII characters.
  67. X * The frequencies are between 0 and 1, so the enteries in the
  68. X * table are between minus infinity and 0.
  69. X * The log of a vanishingly small frequency is represented as
  70. X * zero rather than some large negative number.
  71. X * The expected value of logprob[c] for a randomly selected
  72. X * character, c, is given by logmean.  The variance of logprob[c]
  73. X * is given by logvar.  The standard deviation is in logsd.
  74. X */
  75. Xfloat    logprob[MAXCHAR+1];
  76. Xfloat    logmean, logvar, logsd;
  77. X
  78. X
  79. X/* This array contains the bigram (letter pair) frequencies.
  80. X * That is, biprob[i][j] is the probability that a randomly selected
  81. X * pair of adjacent plaintext characters is Ai, Aj.  Where Ai
  82. X * is the ith letter of the alphabet (0 = 'A' or 'a', and
  83. X * 26 = space or other non-alphabetic).
  84. X * Eventually this will be generalized to include an arbitrary
  85. X * character translation table to handle punctuation and to allow
  86. X * groups of characters such as (, <, {, and [ to be treated the same.
  87. X * 
  88. X * The array slbiprob is the single letter frequencies taken from the
  89. X * same sources as biprob[][].
  90. X */
  91. Xfloat    biprob[MXBIINDEX][MXBIINDEX];
  92. Xfloat    slbiprob[MXBIINDEX];
  93. X
  94. X
  95. X/* The array is used to map from 7-bit ascii to indices in the biprob
  96. X * and related arrays.  The variable nbichars is set to the next index
  97. X * to use in the biprob array.
  98. X */
  99. Xint        char_bimap[MAXCHAR+1];
  100. Xint        nbichars;
  101. X
  102. X
  103. X/* This array contains the base ten logarithms of the letter pair
  104. X * frequencies (biprob[][]).
  105. X * The frequencies are between 0 and 1, so the enteries in the
  106. X * table are between minus infinity and 0.
  107. X * The log of a vanishingly small frequency is represented as
  108. X * zero rather than some large negative number.
  109. X * The expected value of bilogprob[c] for a randomly selected
  110. X * character, c, is given by bilogmean.  The variance of bilogprob[c]
  111. X * is given by bilogvar.  The standard deviation is in bilogsd.
  112. X */
  113. Xfloat    bilogprob[MXBIINDEX][MXBIINDEX];
  114. X
  115. X
  116. X/* This vector contains the base ten logarithms of the single letter
  117. X * frequencies which are derived from biprob[][].
  118. X * They are used to compute the log of the conditional probabilities
  119. X * of letter pairs, given a known value for either the first or
  120. X * second character.
  121. X * Specifically: log( prob(XY given X=Ai) ) equals
  122. X *    log( prob(XY) / prob(Ai) ) which equals 
  123. X *    bilogprob[X][Y] - sllogprob[Ai].
  124. X */
  125. Xfloat    sllogprob[MXBIINDEX];
  126. X
  127. X
  128. X/* The scoring function that uses letter pair frequencies is based
  129. X * on a statistic that has a computable mean and variance (and
  130. X * standard deviation).  The are stored in the following variables.
  131. X */
  132. Xfloat    score2_mean, score2_var, score2_sd, score2_scale;
  133. Xfloat    score1_mean, score1_var, score1_sd, score1_scale;
  134. X
  135. X
  136. X#if STANDALONE
  137. X#define    filename        "/usr/baldwin/Ecrypt/mss-bigram.stats"
  138. Xmain()
  139. X{
  140. X    FILE    *inp;
  141. X
  142. X    load_2stats_from(filename);
  143. X    print_2stats(stdout);
  144. X}
  145. X#endif
  146. X
  147. X
  148. X
  149. X/* Score the given plaintext block.  Returns a floating point number.
  150. X * For now a stud.
  151. X */
  152. Xfloat    score(pblock)
  153. Xint        pblock[];
  154. X{
  155. X    int        pchar;
  156. X    int        i;
  157. X    float    score;
  158. X
  159. X    score = 0.0;
  160. X    for (i = 0 ; i < BLOCKSIZE ; i++)  {
  161. X        pchar = pblock[i];
  162. X        if (pchar == -1)  continue;
  163. X        if (pchar == ' ')            {score += 0.1;}
  164. X        else if (lletter(pchar))    {score += 0.1;}
  165. X        else if (uletter(pchar))    {score += 0.05;}
  166. X        else if (printable(pchar))    {score += 0.02;}
  167. X        else if (pchar == '\t' || pchar == '\n' || pchar == '\f')
  168. X                                    {score += 0.05;}
  169. X        else if ('0' <= pchar && pchar <= '9')
  170. X                                    {score += 0.05;}
  171. X        else                         {score -= 0.4;}
  172. X        }
  173. X    return(score);
  174. X}
  175. X
  176. X
  177. X/* Score a vector of integers that represent characters.
  178. X * The vector is terminated by a value of NONE.
  179. X * The returned score is the number of standard deviations
  180. X * that the observed statistics differs from its expected value.
  181. X * Scores are positive with low scores being better.
  182. X * A negative score indicates an impossible plaintext value.
  183. X */
  184. Xfloat    pvec_1score(pvec)
  185. Xint    *pvec;
  186. X{
  187. X    int        i;
  188. X    int        c;
  189. X    float    tmp, sum, count, score;
  190. X
  191. X    if (!stats1loaded)  {
  192. X        load_1stats_from(letterstats);
  193. X        }
  194. X
  195. X    count = 0.0;
  196. X    sum = 0.0;
  197. X    while (*pvec != NONE)  {
  198. X        count += 1.0;
  199. X        c = *pvec++;
  200. X        if (c != c & CHARMASK)  return(-1.0);
  201. X        tmp = logprob[c & CHARMASK];
  202. X        if (tmp == 0.0)  return(-1.0);
  203. X        sum += tmp;
  204. X        }
  205. X
  206. X    if (count == 0.0)  return(-1.0);
  207. X    tmp = (sum / count) - logmean;
  208. X    tmp = tmp > 0 ? tmp : 0.0 - tmp;
  209. X    score = tmp / (logsd / sqrt(count));
  210. X/*    printf("  dividing by logsd yields %g", score);
  211. X    tmp = tmp * tmp;
  212. X    tmp = (tmp * count) / logvar;
  213. X    tmp = exp(-0.5 * tmp);
  214. X    printf("\nThe exponential yields %g", tmp);
  215. X    printf("\n");
  216. X    score = sqrt(count) * exp((0 - tmp)/2.0);
  217. X*/
  218. X    return(score);
  219. X}
  220. X
  221. X
  222. X/* Score a vector of integers that represent characters.
  223. X * The vector is terminated by a value of NONE.
  224. X * Scoring is based on ratio of observed and expected variance.
  225. X */
  226. Xfloat    var_1score(pvec)
  227. Xint    *pvec;
  228. X{
  229. X    int        i;
  230. X    int        c;
  231. X    float    tmp, sum, count, score;
  232. X
  233. X    if (!stats1loaded)  {
  234. X        load_1stats_from(letterstats);
  235. X        }
  236. X
  237. X    count = 0.0;
  238. X    sum = 0.0;
  239. X    while (*pvec != NONE)  {
  240. X        count += 1.0;
  241. X        c = *pvec++;
  242. X        if (c != c & CHARMASK)  return(0.0);
  243. X        tmp = logprob[c & CHARMASK];
  244. X        if (tmp == 0.0)  return(0.0);
  245. X        tmp = tmp - logmean;
  246. X        tmp = tmp * tmp;
  247. X        sum += tmp;
  248. X        }
  249. X
  250. X    if (count == 0.0)  return(0.0);
  251. X    score = sum / (count * logvar);
  252. X    return(score);
  253. X}
  254. X
  255. X
  256. X/* Score a vector of integers that represent characters.
  257. X * The vector is terminated by a value of NONE.
  258. X * Score is the probability that the given characters
  259. X * were drawn from english.
  260. X * NOTE: doesn't correctly handle repeated letters.
  261. X */
  262. Xfloat    prob_1score(pvec)
  263. Xint    *pvec;
  264. X{
  265. X    int        i;
  266. X    int        c;
  267. X    float    tmp, product, count, score;
  268. X
  269. X    if (!stats1loaded)  {
  270. X        load_1stats_from(letterstats);
  271. X        }
  272. X
  273. X    count = 0.0;
  274. X    product = 1.0;
  275. X    while (*pvec != NONE)  {
  276. X        count += 1.0;
  277. X        c = *pvec++;
  278. X        if (c != c & CHARMASK)  return(0.0);
  279. X        product *= prob[c] * count;
  280. X        }
  281. X
  282. X    if (count == 0.0)  return(0.0);
  283. X    score = product;
  284. X    return(score);
  285. X}
  286. X
  287. X
  288. X/* Score a guess based on letter pair frequencies.
  289. X * The returned score is the number of standard deviations
  290. X * that the observed statistics differs from its expected value.
  291. X * Scores are positive with low scores being better.
  292. X * A negative score indicates an impossible plaintext value.
  293. X */
  294. Xfloat    gsi_2score(gsi)
  295. Xreg        gsinfo    *gsi;
  296. X{
  297. X    float    score;
  298. X    float    total;
  299. X    float    tmp;
  300. X    int        nchars;
  301. X    int        i;
  302. Xreg    int        pos;    
  303. Xreg    int        c;
  304. Xreg    int        center_letter;
  305. X    int        left_letter, right_letter;
  306. X    float    pair_score;
  307. X
  308. X    if (!stats2loaded)  {
  309. X        load_2stats_from(bigramstats);
  310. X        }
  311. X
  312. X    nchars = 0;
  313. X    total = 0.0;
  314. X    for (i = 0 ; (pos = gsi->cpos[i]) != NONE ; i++)  {
  315. X        nchars++;
  316. X        c = (gsi->cguessed)[pos];
  317. X        center_letter = char_bimap[c & CHARMASK];
  318. X        if (sllogprob[center_letter] == 0.0)
  319. X            return(-1.0);
  320. X
  321. X        if (pos == 0) {
  322. X            total += sllogprob[center_letter];
  323. X            }
  324. X        else {
  325. X            c = (gsi->cknown)[pos - 1];
  326. X            if (c == NONE)  {
  327. X                c = (gsi->cguessed)[pos - 1];
  328. X                }
  329. X            if (c == NONE)  {
  330. X                total += sllogprob[center_letter];
  331. X                }
  332. X            else {
  333. X                left_letter = char_bimap[c & CHARMASK];
  334. X                pair_score = bilogprob[left_letter][center_letter];
  335. X                if (pair_score == 0.0)
  336. X                    return(-1.0);
  337. X                total += pair_score - sllogprob[center_letter];
  338. X                }
  339. X            }
  340. X
  341. X        if (pos == (BLOCKSIZE - 1)) {
  342. X            total += sllogprob[center_letter];
  343. X            }
  344. X        else {
  345. X            c = (gsi->cknown)[pos + 1];
  346. X            if (c == NONE)  {
  347. X                c = (gsi->cguessed)[pos + 1];
  348. X                }
  349. X            if (c == NONE)  {
  350. X                total += sllogprob[center_letter];
  351. X                }
  352. X            else {
  353. X                right_letter = char_bimap[c & CHARMASK];
  354. X                pair_score = bilogprob[center_letter][right_letter];
  355. X                if (pair_score == 0.0)
  356. X                    return(-1.0);
  357. X                total += pair_score - sllogprob[center_letter];
  358. X                }
  359. X            }
  360. X        }
  361. X
  362. X    if (nchars == 0)
  363. X        return(-1.0);
  364. X    tmp = (total / nchars) - score2_mean;
  365. X    tmp = tmp > 0.0 ? tmp : 0.0 - tmp;
  366. X    score = tmp / (score2_sd / isqrt[nchars]);
  367. X    return(score);
  368. X}
  369. X
  370. X
  371. X/* Score a guess based on single letter frequencies.
  372. X * The returned score is the number of standard deviations
  373. X * that the observed statistics differs from its expected value.
  374. X * Scores are positive with low scores being better.
  375. X * A negative score indicates an impossible plaintext value.
  376. X */
  377. Xfloat    gsi_1score(gsi)
  378. Xreg        gsinfo    *gsi;
  379. X{
  380. Xreg    int        pos;
  381. X    int        i;
  382. X    int        c;
  383. X    int        nchars;
  384. X    float    sum, score;
  385. Xreg    float    tmp;
  386. X
  387. X    if (!stats1loaded)  {
  388. X        load_1stats_from(letterstats);
  389. X        }
  390. X
  391. X    nchars = 0;
  392. X    sum = 0.0;
  393. X    for (i = 0 ; (pos = gsi->cpos[i]) != NONE ; i++)  {
  394. X        nchars++;
  395. X        c = (gsi->cguessed)[pos];
  396. X        tmp = logprob[c & CHARMASK];
  397. X        if (tmp == 0.0)
  398. X            return(-1.0);
  399. X        sum += tmp;
  400. X        }
  401. X
  402. X    if (nchars == 0)
  403. X        return(-1.0);
  404. X    tmp = (sum / nchars) - logmean;
  405. X    tmp = tmp > 0 ? tmp : 0.0 - tmp;
  406. X    score = tmp / (logsd / isqrt[nchars]);
  407. X
  408. X    return(score);
  409. X}
  410. X
  411. X
  412. X/* Compute expected value of a scoring function given
  413. X * a vector of probabilities for values and a vector of
  414. X * scores for each value.
  415. X */
  416. Xfloat    vec_mean(probvec, scorevec, maxindex)
  417. Xfloat    *probvec;
  418. Xfloat    *scorevec;
  419. Xint        maxindex;
  420. X{
  421. X    int        i;
  422. X    float    mean;
  423. X
  424. X    mean = 0.0;
  425. X    for (i = 0 ; i <= maxindex ; i++) {
  426. X        mean += (*probvec++) * (*scorevec++);
  427. X        }
  428. X    return(mean);
  429. X}
  430. X
  431. X
  432. X/* Compute variance of a scoring function given
  433. X * a vector of probabilities for values and a vector of
  434. X * scores for each value.
  435. X */
  436. Xfloat    vec_variance(probvec, scorevec, maxindex)
  437. Xfloat    *probvec;
  438. Xfloat    *scorevec;
  439. Xint        maxindex;
  440. X{
  441. X    int        i;
  442. X    float    var, mean;
  443. X    float    delta;
  444. X
  445. X    mean = vec_mean(probvec, scorevec, maxindex);
  446. X    var = 0.0;
  447. X    for (i = 0 ; i <= maxindex ; i++) {
  448. X        delta = (*scorevec++) - mean;
  449. X        var += (*probvec++) * (delta * delta);
  450. X        }
  451. X    return(var);
  452. X}
  453. X
  454. X
  455. X/* Read from given stream to set up logprob table and constants
  456. X * logmean and logvar.
  457. X *
  458. X * The table format is:
  459. X * <Total count>
  460. X * <Blankline>
  461. X * <Count><space><One or more slashified characters to share that count>
  462. X *  ...
  463. X * <Count><space><One or more slashified characters to share that count>
  464. X * <Blankline>
  465. X * <EOF>
  466. X */
  467. Xload_1stats(inp)
  468. XFILE    *inp;
  469. X{
  470. X    int        i,n;
  471. X    int        tmp;
  472. X    int        c;
  473. X    float    v, lv, fv;
  474. X    float    etotal, ctotal;
  475. X
  476. X    stats1loaded = TRUE;
  477. X
  478. X    for (i = 0 ; i <= MAXCHAR ; i++)  logprob[i] = 0.0;
  479. X
  480. X    if (fscanf(inp, "%d", &tmp) != 1)  {
  481. X        printf("Error while getting total");
  482. X        return;
  483. X        }
  484. X    etotal = tmp;
  485. X    ctotal = 0.0;
  486. X
  487. X    if (fscanf(inp, "\n") != 0)  {
  488. X        printf("Error while skipping blank line");
  489. X        return;
  490. X        }
  491. X
  492. X    while (TRUE) {
  493. X        if ((n = fscanf(inp, "%d", &tmp)) != 1)  {
  494. X            if (n == 0) break;
  495. X            if (n == EOF) break;
  496. X            printf("Error while getting character count");
  497. X            return;
  498. X            }
  499. X        v = tmp;
  500. X        ctotal += v;
  501. X        fv = v/etotal;
  502. X        if (fv != 0.0)  {lv = log10(fv);}
  503. X        else {lv = 0.0;}
  504. X
  505. X        c = read_char(inp);        /* Skip the space. */
  506. X        while (TRUE) {
  507. X            c = read_char(inp);
  508. X            if (c == EOL)  break;
  509. X            prob[c&CHARMASK] = fv;
  510. X            logprob[c&CHARMASK] = lv;
  511. X            }
  512. X        }
  513. X
  514. X    if (etotal != ctotal) {
  515. X        printf("Expected total is %f.  Actual total is %f.\n",etotal,ctotal);
  516. X        }
  517. X
  518. X    logmean = vec_mean(prob, logprob, MAXCHAR);
  519. X    logvar  = vec_variance(prob, logprob, MAXCHAR);
  520. X    logsd = sqrt(logvar);
  521. X    score1_mean = logmean;
  522. X    score1_var = logvar;
  523. X    score1_sd = logsd;
  524. X    score1_scale = sqrt(2 * PI * score1_var);
  525. X    pmean = vec_mean(prob, prob, MAXCHAR);
  526. X    pvar = vec_variance(prob, prob, MAXCHAR);
  527. X}
  528. X
  529. X
  530. X/* Load the letter pair statistics from the given file name.
  531. X */
  532. Xload_2stats_from(statfname)
  533. Xchar    *statfname;        /* Full path name of file with statistics. */
  534. X{
  535. X    FILE    *inp;
  536. X
  537. X    if ((inp = fopen(statfname, "r")) == NULL) {
  538. X        printf("\nCan't open %s to read letter statistics\n", statfname);
  539. X        exit(0);
  540. X        }
  541. X    load_2stats(inp);
  542. X    fclose(inp);
  543. X}
  544. X
  545. X
  546. X/* Read from given stream to set up bilogprob table and constants
  547. X * bilogmean, bilogsd, and bilogvar.
  548. X *
  549. X * The format of the statistics file is: [This should be more general.]
  550. X * <Total count>
  551. X * <Blankline>
  552. X * <single letter counts>
  553. X * <line with the chars '***'>
  554. X * <double letter counts>
  555. X * <line with the chars '***'>
  556. X * <mean of matrix>
  557. X * <variance of matrix>
  558. X * <standard deviation of matrix>
  559. X * <Blankline>
  560. X * <EOF>
  561. X *
  562. X * Where single letter counts also define the mapping from ascii chars to
  563. X * distinguished letters (i.e., all open brackets are treated the same).
  564. X * The single letter format is:
  565. X * <Count><space><One or more slashified characters to share that count>
  566. X *  ...
  567. X * <Count><space><One or more slashified characters to share that count>
  568. X * NOTE: the first entry should be for a low probability letter because the
  569. X * default mapping for unknown chars is zero.  See code for details.
  570. X *
  571. X * The double letter format is:
  572. X * <Count><space><Representative of first letter group><Rep of second letter>
  573. X *  ...
  574. X * <Count><space><Representative of first letter group><Rep of second letter>
  575. X *
  576. X * For example if 'T' and 't' are treated the same, a double letter entry
  577. X * might look like: "1247 TT" and count for Tt, tT, tt, and TT.
  578. X */
  579. Xload_2stats(inp)
  580. XFILE    *inp;
  581. X{
  582. Xregister    int        i,j;
  583. X    int        n;
  584. X    int        tmp;
  585. X    int        c;
  586. X    int        left_index, right_index;
  587. X    float    v, lv, fv;
  588. X    float    etotal, ctotal;
  589. X    char    linebuf[300];
  590. X
  591. X    stats2loaded = TRUE;
  592. X    nbichars = 0;
  593. X
  594. X    for (i = 0 ; i < MXBIINDEX ; i++)  {
  595. X        sllogprob[i] = 0.0;
  596. X        slbiprob[i] = 0.0;
  597. X        for (j = 0 ; j < MXBIINDEX ; j++)  {
  598. X             bilogprob[i][j] = 0.0;
  599. X            biprob[i][j] = 0.0;
  600. X            }
  601. X        }
  602. X
  603. X    for (i = 0 ; i < MAXCHAR+1 ; i++)
  604. X        char_bimap[i] = 0;        /* Default index if char unknown. */
  605. X
  606. X    if (fscanf(inp, "%d", &tmp) != 1)  {
  607. X        printf("Error while getting total");
  608. X        exit(0);
  609. X        }
  610. X    etotal = tmp;
  611. X
  612. X    if (fscanf(inp, "\n") != 0)  {
  613. X        printf("Error while skipping blank line before single letters");
  614. X        exit(0);
  615. X        }
  616. X
  617. X    ctotal = 0.0;
  618. X    while (TRUE) {
  619. X        if ((n = fscanf(inp, "%d", &tmp)) != 1)  {
  620. X            if (n == 0) break;
  621. X            if (n == EOF) break;
  622. X            printf("Error while getting character count (singles)");
  623. X            exit(0);
  624. X            }
  625. X        v = tmp;
  626. X        ctotal += v;
  627. X        fv = v/etotal;
  628. X        if (fv == 0.0)
  629. X            lv = 0.0;
  630. X        else
  631. X            lv = log10(fv);
  632. X
  633. X        c = read_char(inp);        /* Skip the space. */
  634. X        while (TRUE) {
  635. X            c = read_char(inp);
  636. X            if (c == EOL)  break;
  637. X            char_bimap[c & CHARMASK] = nbichars;
  638. X            slbiprob[nbichars] = fv;
  639. X            sllogprob[nbichars] = lv;
  640. X            }
  641. X        nbichars++;
  642. X        }
  643. X
  644. X    if (etotal != ctotal) {
  645. X        printf("Expected total is %f.  Actual total is %f for singles.\n",
  646. X                etotal, ctotal);
  647. X        exit(0);
  648. X        }
  649. X
  650. X
  651. X    if (fscanf(inp, "***\n") != 0)  {
  652. X        printf("Error on delimiter before letter pairs");
  653. X        exit(0);
  654. X        }
  655. X
  656. X    ctotal = 0.0;
  657. X    while (TRUE) {
  658. X        if ((n = fscanf(inp, "%d", &tmp)) != 1)  {
  659. X            if (n == 0) break;
  660. X            if (n == EOF) break;
  661. X            printf("Error while getting character count (pairs)");
  662. X            exit(0);
  663. X            }
  664. X        v = tmp;
  665. X        ctotal += v;
  666. X        fv = v/etotal;
  667. X        if (fv == 0.0)
  668. X            lv = 0.0;
  669. X        else
  670. X            lv = log10(fv);
  671. X
  672. X        c = read_char(inp);        /* Skip the space. */
  673. X        c = read_char(inp);        /* First letter. */
  674. X        if (c == EOL)  {
  675. X            printf("Line ends before letter pair");
  676. X            exit(0);
  677. X            }
  678. X        left_index = char_bimap[c & CHARMASK];
  679. X        c = read_char(inp);        /* Second letter. */
  680. X        if (c == EOL)  {
  681. X            printf("Line ends in middle of letter pair");
  682. X            exit(0);
  683. X            }
  684. X        right_index = char_bimap[c & CHARMASK];
  685. X
  686. X        biprob[left_index][right_index] = fv;
  687. X        bilogprob[left_index][right_index] = lv;
  688. X        }
  689. X
  690. X    if (etotal != ctotal) {
  691. X        printf("Expected total is %f.  Actual total is %f for pairs.\n",
  692. X                etotal, ctotal);
  693. X        exit(0);
  694. X        }
  695. X
  696. X    if (fscanf(inp, "***\n") == 0)  {
  697. X        if (fscanf(inp, "%f", &score2_mean) != 1)  {
  698. X            printf("Error reading mean.");
  699. X            exit(0);
  700. X            }
  701. X        if (fscanf(inp, "%f", &score2_var) != 1)  {
  702. X            printf("Error reading variance.");
  703. X            exit(0);
  704. X            }
  705. X        if (fscanf(inp, "%f", &score2_sd) != 1)  {
  706. X            printf("Error reading standard deviations.");
  707. X            exit(0);
  708. X            }
  709. X        score2_scale = sqrt(2 * PI * score2_var);
  710. X        approx_init();
  711. X        return;
  712. X        }
  713. X
  714. X    stats2();
  715. X    printf("Mean: %f, Var: %f, SD: %f\n", score2_mean, score2_var, score2_sd);
  716. X}
  717. X
  718. X
  719. X/* Compute scoring statistics for the letter pair frequencies.
  720. X * Uses the globals: biprob[][], sllogbiprob[], and bilogprob[][].
  721. X * Sets gobals: score2_mean, score2_var, score2_sd.
  722. X */
  723. Xstats2()
  724. X{
  725. Xregister    int    i,j,k;
  726. X    float    mean, var;
  727. X    float    weight, score;
  728. X
  729. X    mean = 0.0;
  730. X    var = 0.0;
  731. X    for (i = 0 ; i < nbichars ; i++)
  732. X        for (j = 0 ; j < nbichars ; j++)  {
  733. X            if (slbiprob[j] == 0.0)
  734. X                continue;
  735. X            for (k = 0 ; k < nbichars ; k++) {
  736. X                weight = biprob[i][j] * biprob[j][k] / slbiprob[j];
  737. X                score = bilogprob[i][j] + bilogprob[j][k] - 2 * sllogprob[j];
  738. X                mean += weight * score;
  739. X                var += weight * score * score;
  740. X                }
  741. X            }
  742. X    var -= mean * mean;
  743. X
  744. X    score2_mean = mean;
  745. X    score2_var = var;
  746. X    score2_sd = sqrt(score2_var);
  747. X    score2_scale = sqrt(2 * PI * score2_var);
  748. X
  749. X    approx_init();
  750. X}
  751. X
  752. X
  753. X/* Print the bigram statistics.
  754. X */
  755. Xprint_2stats(out)
  756. XFILE    *out;
  757. X{
  758. X    float    sllog_mean;
  759. X    float    sllog_var;
  760. X    float    lev_mean, lev_var;
  761. X    float    rev_mean, rev_var;
  762. X
  763. X    fprintf(out, "\t\tBigram Statistics\n");
  764. X    fprintf(out, "Score2_mean is %f", score2_mean);
  765. X    fprintf(out, ", score2_var is %f", score2_var);
  766. X    fprintf(out, ", score2_sd is %f", score2_sd);
  767. X    fprintf(out, "\nnbichars is %d", nbichars);
  768. X    fprintf(out, "\n");
  769. X
  770. X    sllog_mean = vec_mean(slbiprob, sllogprob, nbichars);
  771. X    sllog_var = vec_variance(slbiprob, sllogprob, nbichars);
  772. X    fprintf(out, "sllog_mean is %f", sllog_mean);
  773. X    fprintf(out, ", sllog_var is %f", sllog_var);
  774. X    fprintf(out, "\n");
  775. X}
  776. X
  777. X
  778. X
  779. X/* Print the first order log statistics on a stream.
  780. X */
  781. Xprint_1stats(out)
  782. XFILE    *out;
  783. X{
  784. X
  785. X    fprintf(out, "Single letter frequencies\n");
  786. X    fprintf(out, "\nExpected value of prob is %f.  Variance is %f.\n",
  787. X           pmean, pvar);
  788. X    print_stat_tab(out, prob, MAXCHAR);
  789. X
  790. X    fprintf(out, "\nExpected value of logprob is %f.  Variance is %f.\n",
  791. X           logmean, logvar);
  792. X    fprintf(out, "Log of single letter frequencies\n");
  793. X    print_stat_tab(out, logprob, MAXCHAR);
  794. X}
  795. X
  796. X
  797. X/* Dumpa statistics table on to a stream.
  798. X */
  799. Xprint_stat_tab(out, table, maxindex)
  800. XFILE    *out;
  801. Xfloat    table[];
  802. Xint        maxindex;
  803. X{
  804. X    int        i;
  805. X
  806. X    for (i = 0 ; i <= maxindex ; i++) {
  807. X        if (i % 8 == 0)  fprintf(out, "\n");
  808. X        fprintf(out, "%7.4f ", table[i]);
  809. X        }
  810. X    fprintf(out, "\n");
  811. X}
  812. X
  813. X
  814. X/* Load the first order statistics from the given file name.
  815. X */
  816. Xload_1stats_from(statfname)
  817. Xchar    *statfname;
  818. X{
  819. X    FILE    *inp;
  820. X
  821. X    if ((inp = fopen(statfname, "r")) == NULL) {
  822. X        printf("\nCan't open %s to read letter statistics\n", statfname);
  823. X        exit(0);
  824. X        }
  825. X    load_1stats(inp);
  826. X    fclose(inp);
  827. X}
  828. X
  829. END_OF_stats.c
  830. if test 18796 -ne `wc -c <stats.c`; then
  831.     echo shar: \"stats.c\" unpacked with wrong size!
  832. fi
  833. # end of overwriting check
  834. fi
  835. if test -f terminal.c -a "${1}" != "-c" ; then 
  836.   echo shar: Will not over-write existing file \"terminal.c\"
  837. else
  838. echo shar: Extracting \"terminal.c\" \(19285 characters\)
  839. sed "s/^X//" >terminal.c <<'END_OF_terminal.c'
  840. X/* Terminal dependent routines (well, most of them ...)
  841. X *
  842. X * Author: Bob Baldwin, October 1986.
  843. X */
  844. X
  845. X/* 
  846. X * Routines in terminal abstraction:
  847. X *
  848. X *    set_term()
  849. X *        Initialize terminal, clear the screen.
  850. X *
  851. X *    unset_term()
  852. X *        Return terminal to state before set_term().
  853. X *
  854. X *    char2sym(char)
  855. X *        Return the symbol used to display the given char in the
  856. X *        decryption window.
  857. X *
  858. X *    putsym(symbol)
  859. X *        Displays the given symbol on the terminal.  Handles
  860. X *         entering and exiting graphics mode.
  861. X *
  862. X *    getcmd()
  863. X *        Reads stdin for a keystroke and returns
  864. X *        a command integer.
  865. X *
  866. X *    beep()
  867. X *        Cause the terminal to beep or flash.
  868. X */
  869. X
  870. X/* The trick to device independence is to clearly separate
  871. X * internal and external representations.  On the inbound
  872. X * side, we separate KEYSTOKES which generate a sequence
  873. X * of ascii characters (one per keystroke in the simple case),
  874. X * from COMMAND-KEYS such as move-cursor-up.  On the outbound
  875. X * side we separate SYMBOLS from the sequence of ascii characters,
  876. X * called GRAPHICS, used to display the symbol.  Each symbol
  877. X * has a single use by the code, though two symbols might
  878. X * appear the same on the user's terminal.
  879. X */
  880. X
  881. X/* Symbols are represented by integers.  If the integer is
  882. X * greater than 256, then it denotes one of the symbols defined
  883. X * in terminal.h.
  884. X *
  885. X * Commands are represented by two byte integers.  The high byte
  886. X * describes the command (see terminal.h), the low byte is the
  887. X * argument to the command.  For example, the insert char command
  888. X * sets the low byte to the character to be inserted.
  889. X */
  890. X
  891. X/* INTERNALS: symbols and graphics
  892. X *
  893. X * The terminal is assumed to be in one of three modes: normal, graphics,
  894. X * or standout (inverse video).  This abstraction takes care of all the
  895. X * switching between modes and tries to avoid sending redundant escape
  896. X * sequences to the terminal.
  897. X * 
  898. X * Part of the terminal initialization is to build a table that describes
  899. X * how to display each symbol.  Ascii characters (including control chars)
  900. X * pass through unchanged, but symbols are looked up in graphtab.
  901. X * Each entry in the graphics table specifies a terminal mode and a
  902. X * string to print that will display that symbol in the given mode.
  903. X * If necessary a mode switch sequence will be sent before printing the
  904. X * string.
  905. X *
  906. X * The graphics corresponding to symbols can be set by the shell variable
  907. X * 'GRAHPICS' using a format similar to the termcap format.  The two
  908. X * character names of the symbols are defined in the table symnames[],
  909. X * which can be indexed by the symbol codes (see terminal.h).
  910. X * The mapping from symbols to graphics is first set to a default value,
  911. X * and then updated by the values found in the shell variable (if any).
  912. X *
  913. X * The GRAPHICS string consists of a number of entries separated by colon
  914. X * characters.  Each entry have the form xx=\Mccc, where xx is the name
  915. X * of a symbol (see symnames[] below), \M indicates the mode for displaying
  916. X * this symbol (it must be one of \N (for normal), \G (for graphics), or \S
  917. X * (for standout or inverse video)), and ccc is a sequence of characters
  918. X * to send.  To include a colon character in the ccc portion, preceed it
  919. X * by a backslash (i.e., '\').  If the \M is ommitted, it defaults to normal.
  920. X */
  921. X
  922. X/* INTERNALS: keystrokes and commands
  923. X *
  924. X * The table keycmdtab is used to convert a sequence of ascii characters
  925. X * into a command integer.  The table specifies the escape sequences that
  926. X * might be generated by the different command keys.  The getcmd routine
  927. X * will read characters from stdin until it has uniquely identified a
  928. X * command, or decided that there is no match.  If no match is found,
  929. X * the terminal is beeped and matching is restarted with the next character.
  930. X * By default keystrokes turn into self-insert commands.
  931. X *
  932. X * In general the last character of the sequence is returned as the arg.
  933. X * This helps windows assign different meanings to keystokes.  For example
  934. X * The return key can be either an insert-return command or an execute-
  935. X * command-line command.
  936. X */
  937. X
  938. X
  939. X#include    <curses.h>
  940. X#include    <sgtty.h>
  941. X#include    <strings.h>
  942. X#include    "window.h"
  943. X#include    "terminal.h"
  944. X#include    "specs.h"
  945. X
  946. X
  947. X/* Routines from termcap library.
  948. X */
  949. Xextern    char *getenv(), *tgetstr(), *tgoto();
  950. X
  951. X
  952. X/* Screen control strings from termcap entry.
  953. X */
  954. Xchar    *term_is;        /* Terminal initializaion string. */
  955. Xchar    *erase_eol;        /* Erase to end of line. */
  956. Xchar    *erase_eos;        /* Erase to end of screen. */
  957. Xchar    *erase_scr;        /* Erase whole screen. */
  958. Xchar    *cm;            /* Cursor motion. */
  959. Xchar    *start_kp;        /* Start graphics mode. */
  960. Xchar    *end_kp;        /* End graphics mode. */
  961. Xchar    *start_alt;        /* Start graphics mode. */
  962. Xchar    *end_alt;        /* End graphics mode. */
  963. Xchar    *start_so;        /* Start standout mode. */
  964. Xchar    *end_so;        /* End standout mode. */
  965. X
  966. X/* Keymap strings from termcap file.
  967. X */
  968. Xchar    *term_f1;        /* The f1 key. */
  969. Xchar    *term_f2;        /* The f2 key. */
  970. Xchar    *term_f3;        /* The f3 key. */
  971. Xchar    *term_f4;        /* The f4 key. */
  972. Xchar    *term_up;        /* Up arrow. */
  973. Xchar    *term_down;        /* Down arrow. */
  974. Xchar    *term_left;        /* Left arrow. */
  975. Xchar    *term_right;        /* Right arrow. */
  976. X
  977. X
  978. X/* Symbol names for the shell variable 'GRAPHICS'
  979. X * The values must be and'ed with SYMBOLM to make
  980. X * suitable indices for graphtab[].
  981. X */
  982. Xlabelv    symnames[NSYMC + 1] = {
  983. X    {"tb", STAB},        /* Tab */
  984. X    {"na", SNOTASCII},    /* Not ascii */
  985. X    {"lf", SLINEFEED},    /* Linefeed */
  986. X    {"cr", SCARETURN},    /* Carriage return */
  987. X    {"ff", SFORMFEED},    /* Formfeed */
  988. X    {"cc", SCONTCODE},    /* Other control characters */
  989. X    {"uk", SUNKNOWN},    /* Plaintext unknown */
  990. X    {"ul", SUNDERLINE},    /* Pseudo underline char */
  991. X    {"hb", SHORZBAR},    /* Horizontal bar */
  992. X    {"vb", SVERTBAR},    /* Vertical bar */
  993. X    {"ll", SLLCORNER},    /* Lower left corner */
  994. X    {NULL, 0},        /* End flag. */
  995. X};
  996. X
  997. X/* Table of graphics characters initialized for ordinary CRT.
  998. X */
  999. Xsymgraph graphtab[NSYMC];
  1000. X
  1001. X
  1002. X/* Symbol names for the shell variable KEYMAPVAR
  1003. X * A command's index in this table should be one less
  1004. X * than the command code.
  1005. X */
  1006. Xlabelv    cmdnames[] = {
  1007. X    {"up", CGO_UP},
  1008. X    {"do", CGO_DOWN},
  1009. X    {"le", CGO_LEFT},
  1010. X    {"ri", CGO_RIGHT},
  1011. X    {"re", CREFRESH},
  1012. X    {"un", CUNDO},
  1013. X    {"cl", CCLRLINE},
  1014. X    {"ws", CWRDSRCH},
  1015. X    {"df", CDELF},
  1016. X    {"db", CDELB},
  1017. X    {"pr", CPREVBLOCK},
  1018. X    {"ne", CNEXTBLOCK},
  1019. X    {"ac", CACCEPT},
  1020. X    {"ex", CEXECUTE},
  1021. X    {"--", CINSERT},        /* Should not be in keymap var. */
  1022. X    {"ta", CTRYALL},
  1023. X    {"jc", CJUMPCMD},
  1024. X    {NULL, 0},
  1025. X};
  1026. X
  1027. X/* Table of keystroke commands.
  1028. X * Self-insert commands are the default.
  1029. X * There can be several keystrokes that generate the same command.
  1030. X * To insert control chars, they must be quoted, see QUOTEC.
  1031. X * The table is terminated by an entry with c_seq == NULL.
  1032. X */
  1033. X#define    QUOTEC    (CNTRL & 'Q')
  1034. Xkeycmd    keycmdtab[100];
  1035. Xkeycmd    *keycmdp;        /* Pointer to next free entry. */
  1036. X
  1037. X
  1038. X
  1039. X/* Saved process control characters.
  1040. X */
  1041. Xstruct    tchars    saved_tchars;
  1042. X
  1043. X
  1044. X/* Buffer for termcap entry. */
  1045. X#define TBUFSIZ 1024
  1046. Xchar    buf[TBUFSIZ];
  1047. Xchar    free_buf[1000], *fr;        /* Must be global, see tgetstr() */
  1048. X
  1049. X
  1050. X/* Current terminal mode. */
  1051. Xint    termmode = -1;
  1052. X
  1053. X
  1054. X/* Set up the terminal. This package now makes calls to both curses
  1055. X * and termcap subroutine packages, although the old code is used
  1056. X * for screen refresh.
  1057. X */
  1058. Xset_term()
  1059. X{
  1060. X    printf("\n\nInitializing terminal ...");
  1061. X    fflush(stdout);
  1062. X
  1063. X    get_termstrs();
  1064. X    get_genv();
  1065. X    get_kenv();
  1066. X    savetty();
  1067. X    crmode();
  1068. X    noecho();
  1069. X    noflow();
  1070. X    Puts(term_is);
  1071. X    Puts(start_kp);
  1072. X    enter_mode(SMNORMAL);
  1073. X
  1074. X    printf(" done.\n");
  1075. X
  1076. X    clrscreen();
  1077. X}
  1078. X
  1079. X
  1080. X/* Get keystroke characters, build keymap.
  1081. X * The earlier entries have priority, so fill them in from
  1082. X * the shell var, then add defaults from a string then termcap.
  1083. X */
  1084. Xget_kenv()
  1085. X{
  1086. X    char    *kenv;
  1087. X    char    tcapstr[1000];
  1088. X
  1089. X    keycmdp = keycmdtab;
  1090. X    kenv = getenv(KEYMAPVAR);
  1091. X    if (kenv != NULL)
  1092. X          read_keymap(kenv);
  1093. X    kenv_termcap(tcapstr);
  1094. X    read_keymap(tcapstr);
  1095. X    read_keymap(DKEYMAP);
  1096. X}
  1097. X
  1098. X
  1099. X/* Build a keymap string in the given buffer from the info
  1100. X * in the termcap file.
  1101. X * The string format is like: "up=\Eu:do=\033d".
  1102. X */
  1103. Xkenv_termcap(str)
  1104. Xchar    *str;
  1105. X{
  1106. X    *str = NULL;
  1107. X
  1108. X    if (term_up != NULL)  {
  1109. X        strcat(str, cmdnames[CGO_UP - 1].label);
  1110. X        strcat(str, "=");
  1111. X        strcat(str, term_up);
  1112. X        strcat(str, ":");
  1113. X    }
  1114. X    if (term_down != NULL)  {
  1115. X        strcat(str, cmdnames[CGO_DOWN - 1].label);
  1116. X        strcat(str, "=");
  1117. X        strcat(str, term_down);
  1118. X        strcat(str, ":");
  1119. X    }
  1120. X    if (term_left != NULL)  {
  1121. X        strcat(str, cmdnames[CGO_LEFT - 1].label);
  1122. X        strcat(str, "=");
  1123. X        strcat(str, term_left);
  1124. X        strcat(str, ":");
  1125. X    }
  1126. X    if (term_right != NULL)  {
  1127. X        strcat(str, cmdnames[CGO_RIGHT - 1].label);
  1128. X        strcat(str, "=");
  1129. X        strcat(str, term_right);
  1130. X        strcat(str, ":");
  1131. X    }
  1132. X    if (term_f1 != NULL)  {
  1133. X        strcat(str, cmdnames[CPREVBLOCK - 1].label);
  1134. X        strcat(str, "=");
  1135. X        strcat(str, term_f1);
  1136. X        strcat(str, ":");
  1137. X    }
  1138. X    if (term_f2 != NULL)  {
  1139. X        strcat(str, cmdnames[CNEXTBLOCK - 1].label);
  1140. X        strcat(str, "=");
  1141. X        strcat(str, term_f2);
  1142. X        strcat(str, ":");
  1143. X    }
  1144. X    if (term_f3 != NULL)  {
  1145. X        strcat(str, cmdnames[CACCEPT - 1].label);
  1146. X        strcat(str, "=");
  1147. X        strcat(str, term_f3);
  1148. X        strcat(str, ":");
  1149. X    }
  1150. X    if (term_f4 != NULL)  {
  1151. X        strcat(str, cmdnames[CJUMPCMD - 1].label);
  1152. X        strcat(str, "=");
  1153. X        strcat(str, term_f4);
  1154. X        strcat(str, ":");
  1155. X    }
  1156. X}
  1157. X
  1158. X
  1159. X
  1160. X/* Add key bindings from the given string to the keycmdtab.
  1161. X */
  1162. Xread_keymap(var)
  1163. Xchar    *var;
  1164. X{
  1165. X    int    cmd_code;
  1166. X
  1167. X    while (*var != NULL)  {
  1168. X        if (! read_varlabel(&var, cmdnames, &cmd_code))  {
  1169. X            if (*var == NULL)
  1170. X                  break;
  1171. X            disperr("Can't parse label in read_keymap.");
  1172. X            exit(1);
  1173. X        }
  1174. X
  1175. X        keycmdp->c_code = cmd_code;
  1176. X        if (! read_varval(&var, &(keycmdp->c_seq)))  {
  1177. X            disperr("keymap value has bad format.");
  1178. X            exit(1);
  1179. X        }
  1180. X        keycmdp++;
  1181. X    }
  1182. X}
  1183. X
  1184. X
  1185. X/* Get graphics characters.
  1186. X * Set to defaults, then read changes from shell var (if any).
  1187. X */
  1188. Xget_genv()
  1189. X{
  1190. X    char    *genv;
  1191. X
  1192. X    read_graphics(DGRAPHICS);
  1193. X    genv = getenv(GRAPHICSVAR);
  1194. X    if (genv == NULL)
  1195. X          return;
  1196. X    read_graphics(genv);
  1197. X}
  1198. X
  1199. X
  1200. X/* Read graphics map from the given string.
  1201. X */
  1202. Xread_graphics(var)
  1203. Xchar    *var;
  1204. X{
  1205. X    int    sym_idx;
  1206. X
  1207. X    while (*var != NULL)  {
  1208. X        if (! read_varlabel(&var, symnames, &sym_idx))  {
  1209. X            if (*var == NULL)
  1210. X                  break;
  1211. X            disperr("Can't parse label in GRAPHICSMAP.");
  1212. X            exit(1);
  1213. X        }
  1214. X
  1215. X        if ((var[0] != '\\') || (index(GVARMODES, var[1]) == 0))  {
  1216. X            disperr("GRAPHICSMAP value has bad mode.");
  1217. X            exit(1);
  1218. X         }
  1219. X        sym_idx &= SYMBOLM;
  1220. X        graphtab[sym_idx].s_mode = var[1] & CHARM;
  1221. X        var++, var++;
  1222. X
  1223. X        if (! read_varval(&var, &(graphtab[sym_idx].s_seq)))  {
  1224. X            disperr("GRAPHICSMAP val has bad format.");
  1225. X            exit(1);
  1226. X        }
  1227. X    }
  1228. X}
  1229. X
  1230. X
  1231. X/* Advance to the next label in strp, look the label up in the
  1232. X * labeltab, and set *valp to the value in the labeltab.
  1233. X * Return with *strp pointing after '=' that follows the label.
  1234. X * Return TRUE is parses ok, else return FALSE.
  1235. X * If string empty, return false and set *strp to point to a NULL.
  1236. X */
  1237. Xint read_varlabel(strp, labeltab, valp)
  1238. Xchar    **strp;
  1239. Xlabelv    *labeltab;
  1240. Xint    *valp;
  1241. X{
  1242. X    char    *str;
  1243. X    labelv    *lp;
  1244. X
  1245. X    for (str = *strp ; *str && index(VARSEP, *str) != 0 ; str++ );
  1246. X
  1247. X    for (lp = labeltab ; lp->label != NULL ; lp++)  {
  1248. X        if (substrp(str, lp->label))  {
  1249. X            *valp = lp->value;
  1250. X            str = index(str, '=');
  1251. X            if (str == NULL)
  1252. X                  return(FALSE);
  1253. X            str++;
  1254. X            *strp = str;
  1255. X            return(TRUE);
  1256. X        }
  1257. X    }
  1258. X    *strp = str;
  1259. X    return(FALSE);
  1260. X}
  1261. X
  1262. X
  1263. X/* Read a string value from a shell var string.
  1264. X * Return with *strp pointing after the string,
  1265. X * fill in valp with a pointer to a copy of the value string
  1266. X * on the heap.
  1267. X * Return TRUE if things go ok.
  1268. X */
  1269. Xint read_varval(strp, valp)
  1270. Xchar    **strp;
  1271. Xchar    **valp;
  1272. X{
  1273. X    char    buf[100], *bp;
  1274. X    char    *var;
  1275. X
  1276. X    var = *strp;
  1277. X    bp = buf;
  1278. X    while ((*var != NULL) && (index(VARTERM, *var) == NULL))  {
  1279. X        *bp = read_slashed(&var);
  1280. X               bp++;
  1281. X        }
  1282. X    *bp = 0;
  1283. X    *valp = savestr(buf);
  1284. X    *strp = var;
  1285. X    return (TRUE);
  1286. X}
  1287. X
  1288. X
  1289. X/* Read the given (slashified) string and return a character.
  1290. X * Advance *strp over chars read.
  1291. X * Handle \\, \001, \n, \t, \r.
  1292. X * The symbol \E maps to escape (\033).
  1293. X * An unexpected char after the slash is just returned.
  1294. X */
  1295. Xint read_slashed(strp)
  1296. Xchar    **strp;
  1297. X{
  1298. X    char    *str;
  1299. X    char    c;
  1300. X
  1301. X    str = *strp;
  1302. X    if (*str != '\\')  {
  1303. X        *strp = (*strp) + 1;
  1304. X          return (*str);
  1305. X    }
  1306. X    str++;
  1307. X    c = *str;
  1308. X    switch (c)  {
  1309. X      default:
  1310. X        if (index(DIGITS, c) == NULL)
  1311. X              break;
  1312. X        c -= '0';
  1313. X        if (index(DIGITS, str[1]) == NULL)
  1314. X              break;
  1315. X        str++;
  1316. X        c = (c * 8) + (*str - '0');
  1317. X        if (index(DIGITS, str[1]) == NULL)
  1318. X              break;
  1319. X        str++;
  1320. X        c = (c * 8) + (*str - '0');
  1321. X        break;
  1322. X
  1323. X      case 'n':
  1324. X        c = '\n';
  1325. X        break;
  1326. X
  1327. X      case 't':
  1328. X        c = '\t';
  1329. X        break;
  1330. X
  1331. X      case 'E':
  1332. X        c = '\033';
  1333. X        break;
  1334. X
  1335. X      case 'f':
  1336. X        c = '\f';
  1337. X        break;
  1338. X
  1339. X      case 'r':
  1340. X        c = '\r';
  1341. X        break;
  1342. X    }
  1343. X    *strp = str + 1;
  1344. X      return (c);
  1345. X}
  1346. X
  1347. X
  1348. X/* Turn off flow control characters.
  1349. X */
  1350. Xnoflow()
  1351. X{
  1352. X    struct    tchars    new_tchars;
  1353. X    
  1354. X    /* Turn off C-Q, C-S flow control. */
  1355. X    if (ioctl(0, TIOCGETC, &saved_tchars) < 0)  {
  1356. X        perror("noflow iocl get");
  1357. X        exit(1);
  1358. X    }
  1359. X    new_tchars = saved_tchars;
  1360. X    new_tchars.t_stopc = -1;
  1361. X    new_tchars.t_startc = -1;
  1362. X    if (ioctl(0, TIOCSETC, &new_tchars) < 0)  {
  1363. X        perror("noflow iocl set");
  1364. X        exit(1);
  1365. X    }
  1366. X}
  1367. X
  1368. X
  1369. X/* Restore the flow control characters.
  1370. X */
  1371. Xrestore_flow()
  1372. X{
  1373. X    if (ioctl(0, TIOCSETC, &saved_tchars) < 0)  {
  1374. X        perror("restore_flow iocl set");
  1375. X        exit(1);
  1376. X    }
  1377. X}
  1378. X
  1379. X
  1380. X/* Read in the termcap strings.
  1381. X */
  1382. Xget_termstrs()
  1383. X{
  1384. X    char    *term;
  1385. X    int    res;
  1386. X
  1387. X    fr=free_buf;
  1388. X    term = getenv("TERM");
  1389. X    if (term == NULL)  {
  1390. X        disperr("The shell variable TERM is not defined.");
  1391. X        exit(1);
  1392. X    }
  1393. X    res = tgetent(buf,term);
  1394. X    switch (res)  {
  1395. X      case -1:
  1396. X        disperr("Can't open termcap file.");
  1397. X        exit(1);
  1398. X
  1399. X      case 0:
  1400. X        disperr("No termcap entry for your terminal.");
  1401. X        exit(1);
  1402. X
  1403. X      default:
  1404. X        break;
  1405. X    }           
  1406. X
  1407. X    term_is = tgetstr("is", &fr);
  1408. X    if (term_is == NULL)
  1409. X          term_is = "";
  1410. X    erase_eol = tgetstr("ce", &fr);
  1411. X    erase_eos = tgetstr("cd", &fr);
  1412. X    erase_scr = tgetstr("cl", &fr);
  1413. X    start_so = tgetstr("so", &fr);
  1414. X    end_so = tgetstr("se", &fr);
  1415. X    start_alt = tgetstr("as", &fr);
  1416. X    end_alt = tgetstr("ae", &fr);
  1417. X    if (start_alt == 0  ||  end_alt == 0) {
  1418. X        start_alt = "\033F";               /* VT100 default. */
  1419. X        end_alt = "\033G";
  1420. X    }
  1421. X    cm = tgetstr("cm", &fr);        /* for cursor positioning */
  1422. X    start_kp = tgetstr("ks", &fr);
  1423. X    end_kp = tgetstr("ke", &fr);
  1424. X
  1425. X    if ((term_is == NULL) || (erase_eol == NULL) ||
  1426. X        (erase_eos == NULL) || (erase_scr == NULL) ||
  1427. X        (cm == NULL) ||
  1428. X        (end_kp == NULL) || (start_kp == NULL) ||
  1429. X        (end_alt == NULL) || (start_alt == NULL) ||
  1430. X        (end_so == NULL) || (start_so == NULL) )  {
  1431. X        disperr("A required termcap capability is missing.");
  1432. X        disperr("\t one of: ce, cd, cl, so, se, cm, ks, ke.");
  1433. X        exit(1);
  1434. X    }
  1435. X
  1436. X    /* Now get entries for keymap, NULL means no such entry.
  1437. X     */
  1438. X    term_f1 = tgetstr("k1", &fr);
  1439. X    term_f2 = tgetstr("k2", &fr);
  1440. X    term_f3 = tgetstr("k3", &fr);
  1441. X    term_f4 = tgetstr("k4", &fr);
  1442. X    term_up = tgetstr("ku", &fr);
  1443. X    term_down = tgetstr("kd", &fr);
  1444. X    term_left = tgetstr("kl", &fr);
  1445. X    term_right = tgetstr("kr", &fr);
  1446. X}
  1447. X
  1448. X
  1449. X/* Restore the terminal to its original mode.
  1450. X */
  1451. Xunset_term()
  1452. X{
  1453. X    enter_mode(SMNORMAL);
  1454. X    Puts(end_kp);        /* Can't tell if this is original. */
  1455. X    fflush(stdout);
  1456. X    nocrmode();
  1457. X    echo();
  1458. X    restore_flow();
  1459. X    resetty();
  1460. X}
  1461. X
  1462. X
  1463. X/* Return the symbol used to display the given char in the
  1464. X * decryption window.
  1465. X */
  1466. Xint  char2sym(pchar)
  1467. Xint    pchar;
  1468. X{
  1469. X     int    gchar;
  1470. X
  1471. X    if (printable(pchar))        {gchar = pchar;}
  1472. X    else if (pchar == -1)         {gchar = SUNKNOWN;}
  1473. X    else if (notascii(pchar))    {gchar = SNOTASCII;}
  1474. X    else if (pchar == '\n')        {gchar = SLINEFEED;}
  1475. X    else if (pchar == '\r')        {gchar = SCARETURN;}
  1476. X    else if (pchar == '\f')        {gchar = SFORMFEED;}
  1477. X    else if (pchar == '\t')        {gchar = STAB;}
  1478. X    else                {gchar = SCONTCODE;}
  1479. X    return (gchar);
  1480. X}
  1481. X
  1482. X
  1483. X/* Displays the given symbol on the terminal.  Handles
  1484. X * entering and exiting graphics or standout mode.
  1485. X */
  1486. Xputsym(symbol)
  1487. Xint    symbol;
  1488. X{
  1489. X    int        symcode;
  1490. X    symgraph    *gp;
  1491. X
  1492. X    if (! graphic(symbol))  {
  1493. X        enter_mode(SMNORMAL);
  1494. X        putchar(symbol & CHARM);
  1495. X        return;
  1496. X    }
  1497. X    symcode = symbol & SYMBOLM;
  1498. X    if (symcode >= NSYMC)  {
  1499. X        disperr("Bad symbol code in putsym.");
  1500. X        return;
  1501. X    }
  1502. X    gp = &graphtab[symcode];
  1503. X    enter_mode(gp->s_mode);
  1504. X    Puts(gp->s_seq);
  1505. X}
  1506. X
  1507. X
  1508. X/* Enter a particular mode.  If necessary send escape sequence
  1509. X * to the terminal.  Handle terminating the previous mode.
  1510. X */
  1511. Xenter_mode(mode)
  1512. Xint    mode;
  1513. X{
  1514. X    if (termmode == mode)
  1515. X          return;
  1516. X
  1517. X    switch (termmode)  {
  1518. X      case SMNORMAL:
  1519. X        break;
  1520. X
  1521. X      case SMGRAPHIC:
  1522. X        Puts(end_alt);
  1523. X        break;
  1524. X
  1525. X      case SMSTANDOUT:
  1526. X        Puts(end_so);
  1527. X        break;
  1528. X
  1529. X      default:
  1530. X        Puts(end_so);
  1531. X        Puts(end_alt);
  1532. X        break;
  1533. X    }
  1534. X
  1535. X    termmode = mode;
  1536. X
  1537. X    switch (termmode)  {
  1538. X      case SMNORMAL:
  1539. X        break;
  1540. X
  1541. X      case SMGRAPHIC:
  1542. X        Puts(start_alt);
  1543. X        break;
  1544. X
  1545. X      case SMSTANDOUT:
  1546. X        Puts(start_so);
  1547. X        break;
  1548. X
  1549. X      default:
  1550. X        disperr("Bad terminal mode.");
  1551. X        break;
  1552. X    }
  1553. X}
  1554. X
  1555. X
  1556. X/* Return values from srch_ktab().
  1557. X */
  1558. X#define SK_SUBSTR    -1
  1559. X#define SK_NOMATCH    -2
  1560. X
  1561. X
  1562. X/* Search the key command table for the given keystroke.
  1563. X * If no match, return SK_NOMATCH (which is < 0).
  1564. X * If the keystroke is the prefix for one or more commands,
  1565. X * return SK_SUBSTR (which is < 0).
  1566. X * If an exact match is found, return the index ( >= 0) of
  1567. X * the entry that matched.
  1568. X */
  1569. Xint srch_ktab(ktab, stroke)
  1570. Xkeycmd    ktab[];
  1571. Xchar    *stroke;
  1572. X{
  1573. X    int    i;
  1574. X    int    nsubstr = 0;        /* Number of close entries */
  1575. X
  1576. X    for (i = 0 ; ktab[i].c_seq != NULL ; i++)  {
  1577. X        if (strcmp(ktab[i].c_seq, stroke) == 0)
  1578. X              return(i);
  1579. X        if (substrp(ktab[i].c_seq, stroke))
  1580. X              nsubstr++;
  1581. X    }
  1582. X    if (nsubstr > 0)
  1583. X          return (SK_SUBSTR);
  1584. X    return (SK_NOMATCH);
  1585. X}
  1586. X
  1587. X
  1588. X/* Return TRUE if the model string starts with the given string.
  1589. X * Return false if strlen(given) > strlen(model).
  1590. X */
  1591. Xint substrp(model, given)
  1592. Xchar    *model;
  1593. Xchar    *given;
  1594. X{
  1595. X    for ( ; (*model != 0) && (*given != 0) ; model++, given++)  {
  1596. X        if (*model != *given)
  1597. X              return (FALSE);
  1598. X    }
  1599. X    if (*given == 0)
  1600. X          return (TRUE);
  1601. X    return (FALSE);
  1602. X}
  1603. X
  1604. X
  1605. X/* Read a keystroke from stdin and return the command for it.
  1606. X *
  1607. X * Single character keystrokes not found in the table generate
  1608. X * self-insert commands.
  1609. X * Control characters other than \n, and \t must be quoted in order
  1610. X * to generate self-insert commands.  To quote a char, preceed it
  1611. X * by the QUOTEC character.
  1612. X * Multi character keystrokes should end in an exact match.  If not,
  1613. X * throw away the char that caused no matches in the keycmdtab,
  1614. X * beep the terminal, and start over.
  1615. X */
  1616. Xint getcmd()
  1617. X{
  1618. X    char    keystroke[10];        /* Chars in keystroke. */
  1619. X    int    nchars;            /* Length of keystroke[]. */
  1620. X    int    c;
  1621. X    int    index;            /* Cmd index in keycmdtab. */
  1622. X    int    code;            /* Cmd code. */
  1623. X
  1624. X  start_over:
  1625. X    nchars = 0;
  1626. X    keystroke[0] = 0;
  1627. X
  1628. X    while (TRUE)  {
  1629. X        c = getchar();
  1630. X        keystroke[nchars++] = c;
  1631. X        keystroke[nchars] = 0;
  1632. X        index = srch_ktab(keycmdtab, keystroke);
  1633. X        switch (index)  {
  1634. X          case SK_SUBSTR:
  1635. X            continue;
  1636. X
  1637. X          case SK_NOMATCH:
  1638. X            if (nchars != 1)  {
  1639. X                beep();
  1640. X                goto start_over;
  1641. X            }
  1642. X            code = CINSERT;
  1643. X            if (c == QUOTEC)  {
  1644. X                c = getchar();
  1645. X                break;
  1646. X            }
  1647. X            else if (printable(c))  {
  1648. X                break;
  1649. X            }
  1650. X            else if ((c != LINEFEED) && (c != TAB))  {
  1651. X                beep();
  1652. X                goto start_over;
  1653. X            }
  1654. X            break;
  1655. X            
  1656. X          default:
  1657. X            if (index < 0)  {
  1658. X                disperr("Bad keycmdtab index.");
  1659. X            }
  1660. X            code = keycmdtab[index].c_code;
  1661. X            break;
  1662. X        }
  1663. X    return ((code << CMDSHIFT) | (c & CHARM));
  1664. X    }
  1665. X}
  1666. X
  1667. X
  1668. X/* Cause the terminal to beep.
  1669. X */
  1670. Xbeep()
  1671. X{
  1672. X    Puts("\007");            /* C-G */
  1673. X}
  1674. X
  1675. X
  1676. X/* Save a copy of the given string on the heap.
  1677. X * Return pointer to copy.
  1678. X */
  1679. Xchar *savestr(s)
  1680. Xregister char    *s;
  1681. X{
  1682. X    char     *p;
  1683. X    register char    *t;
  1684. X
  1685. X    if (s == NULL)
  1686. X        return( NULL );
  1687. X    t = p = (char*) calloc(strlen(s) + 1, 1);
  1688. X    if (t == NULL)
  1689. X        return(NULL);
  1690. X    while (*t++ = *s++);
  1691. X    return(p); 
  1692. X}
  1693. END_OF_terminal.c
  1694. if test 19285 -ne `wc -c <terminal.c`; then
  1695.     echo shar: \"terminal.c\" unpacked with wrong size!
  1696. fi
  1697. # end of overwriting check
  1698. fi
  1699. echo shar: End of archive 8 \(of 11\).
  1700. cp /dev/null ark8isdone
  1701. MISSING=""
  1702. for I in 1 2 3 4 5 6 7 8 9 10 11 ; do
  1703.     if test ! -f ark${I}isdone ; then
  1704.     MISSING="${MISSING} ${I}"
  1705.     fi
  1706. done
  1707. if test "${MISSING}" = "" ; then
  1708.     echo You have unpacked all 11 archives.
  1709.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1710. else
  1711.     echo You still need to unpack the following archives:
  1712.     echo "        " ${MISSING}
  1713. fi
  1714. ##  End of shell archive.
  1715. exit 0
  1716.